#!/usr/bin/python2.4
#
# Copyright 2010 Google Inc.

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.


"""Contains the genotype representation of the solution.

Solution object contains the genotype representation of the solution
to evolutionary algorithm. For our purpose, the genotype is a numpy
ndarray of boolean type that denotes the selection of each test target.
For example, if a test target i is selected (i.e. prioritised) by a
solution, the i_th element of the ndarray is True.

To avoid duplicate solutions (those that depict the same selection of
test gargets), it is important that the hash of a Solution instance
reflect the actual selection of test targets (i.e. the indexes of the
set elements in the ndarray). Currently, Solution object uses the hash
of picked string of the ndarray. It works, but it may not be the fastest.
"""

__author__ = 'ntrolls@gmail.com (Shin Yoo)'

import pickle
import random
import comparators
import numpy


class Solution(object):
  """Stores the solution genotype along with objective values."""

  def __init__(self, problem=None, gene=None):
    self.problem = problem
    self.objectives = []
    self.objectivenames = []
    for i in xrange(problem.numberofobjectives):
      self.objectivenames.append(problem.objectivenames[i])
      self.objectives.append(0)
    if not gene is None:
      self.gene = gene
    else:
      ## when the genotype representation is not given, the gene
      ## is initialised randomly
      self.gene = numpy.zeros(problem.numberoftests, dtype=bool)
      for i in xrange(problem.numberoftests):
        self.gene[i] = (random.random() > 0.5)
    self.distance = 0

  def DominatedBy(self, solutionset):
    comparator = comparators.DominanceComparator()
    for other in solutionset:
      if comparator.Compare(self, other) == 1:
        return True
    return False

  def GetSolutionsDominatedByThis(self, solutionset):
    dominated = set()
    comparator = comparators.DominanceComparator()
    for other in solutionset:
      if comparator.Compare(self, other) == -1:
        dominated.add(other)
    return dominated

  def GetObjectiveValueByName(self, name):
    return self.objectives[self.objectivenames.index(name)]

  def __repr__(self):
    return str(self.objectives)

  def __eq__(self, other):
    return self.gene.__eq__(other.gene).prod()

  def __ne__(self, other):
    return self.gene.__ne__(other.gene).prod()

  def __hash__(self):
    return pickle.dumps(self.gene).__hash__()
